Add opt-in file persistence to the memory plugin (#111)#315
Merged
codelion merged 3 commits intoJul 5, 2026
Merged
Conversation
…elligence#111) The memory plugin builds a fresh in-RAM Memory() per request, so extracted memories never survive across calls. This adds an opt-in file-backed store, gated on the OPTILLM_MEMORY_FILE env var: - Memory(persist_path=...) loads saved items on init and writes after each add() - run() reads the path from OPTILLM_MEMORY_FILE; unset => behaviour unchanged - loads degrade gracefully on missing/corrupt/non-list files (logged, no raise) - saves are atomic (temp file + os.replace) and bounded by max_size - README documents the env var; unit test covers round-trip, corrupt/missing files, max_size truncation, and the default no-I/O path
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a security-scan workflow that runs the Frame neuro-symbolic SAST tool (lambdasec/frame, pinned) on the Python files changed by a pull request. Scanning only the PR's added/modified files surfaces issues introduced by the change without failing on pre-existing findings elsewhere in the tree. The job fails only on high/critical severity, so lower-confidence categories (e.g. insecure_random on algorithmic sampling) do not block merges. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds opt-in file-backed persistence to the
memoryplugin, so extracted memories can survive across requests. Closes #111.Today
memory_plugin.run()builds a fresh in-RAMMemory()on every request, so nothing is retained between calls. This adds an optional persistent store, gated behind a single environment variable.How
Memory(persist_path=...)loads any previously saved items on init and writes after everyadd().run()reads the path from the newOPTILLM_MEMORY_FILEenv var (matching the existingOPTILLM_*env-var convention). When it is unset,persist_pathisNoneand behaviour is byte-for-byte unchanged — the default path stays fully in-RAM and touches no disk._load_from_file: a missing file is a normal first run; a corrupt / non-list JSON payload is logged and degrades to an empty store instead of raising, so persistence can never fail a request at startup. Loaded items are filtered to strings and truncated tomax_size(most recent kept)._save_to_file: atomic write via a temp file in the same directory +os.replace, so a crash mid-write can't corrupt an existing store. AnyOSErroris logged and swallowed.max_size(100) eviction.Usage
Design note
The linked issue suggested a JSON
save_to_file/load_from_filepair, and you greenlit "add a plugin that supports this." I implemented it as an opt-in extension of the existing memory plugin rather than a separate plugin, to avoid duplicating the extraction/retrieval logic — the default behaviour is untouched. Happy to split it into a standalone plugin instead if you'd prefer that shape.Tests
tests/test_plugins.py::test_memory_plugin_persistence(runs in the existing no-server unit-test job) covers: round-trip persistence, missing file, corrupt file, non-list payload,max_sizetruncation on load, and that the default (nopersist_path) performs no file I/O.